package scheme;
/**
 * @Classname RSU
 * @Description
 * @Created by kevin
 */
import accessstruct.AccessControlParameter;
import accessstruct.lsss.LSSSLW10Engine;
import accessstruct.lsss.LSSSPolicyEngine;
import util.ConfigFileName;
import accessstruct.Node;
import accessstruct.Tool;
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;

import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.math.BigInteger;

import static accessstruct.Tool.loadPropFromFile;
import static java.lang.Integer.valueOf;

public class RSU {

    /**
     * 属性认证协议
     * @param config
     * @param userID
     * @param aaNums
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static Boolean attAuth(ConfigFileName config,String userID,String[] AttrList,int aaNums,int[][] AccessPolicy,String[] rhos) throws Exception {
        /*********************************************获取公共参数*******************************************************/
        //准备工作获取公参
        Pairing bp = PairingFactory.getPairing(config.getPairingParametersFileName());
        Properties GPProp = Tool.loadPropFromFile(config.getGPFileName());
        String gString = GPProp.getProperty("g");
        Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();
        Element zero = bp.getZr().newZeroElement().getImmutable();
        Element one = bp.pairing(g,g).powZn(zero);

        Properties ctProp = accessstruct.Tool.loadPropFromFile(config.getCtFileName());
        Properties AUKProp = accessstruct.Tool.loadPropFromFile(config.getCSPUAKFileName());
        AccessControlParameter test = LSSSLW10Engine.generateAccessControl(AccessPolicy ,rhos);
        Map<String, Element> ci = LSSSPolicyEngine.reconstructOmegas(bp,AttrList,test);//这个Ci是1其实可以不用乘
        Element verifyId = bp.getGT().newOneElement().getImmutable();

        Element H_uid = bp.getG1().newElement();
        H_uid.setFromHash(userID.getBytes(), 0, userID.getBytes().length);
        H_uid = H_uid.getImmutable();

        for(int aid = 1; aid <= aaNums;aid++){
            int averageLen =  AttrList.length/aaNums;
            String [] attInAid = new String[averageLen];
            for(int j = 0;j<averageLen;j++){
                attInAid[j] = AttrList[(aid-1)*averageLen + j];
            }
            for(String att:attInAid){

                String Di1String = ctProp.getProperty("D_" + att + "_1-" +aid+"-"+ userID);
                Element D_i_1 = bp.getGT().newElementFromBytes(Base64.getDecoder().decode(Di1String)).getImmutable();
                String Di2String = ctProp.getProperty("D_" + att + "_2-" +aid+"-"+ userID);
                Element D_i_2 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(Di2String)).getImmutable();
                String Ci3String = ctProp.getProperty("C" + att + "3-"+aid );
                Element C_i_3 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(Ci3String)).getImmutable();
                String UAKiString = AUKProp.getProperty("UAK_"+att+"_"+userID);
                Element UAKi = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(UAKiString)).getImmutable();
                Element B = D_i_1.mul(bp.pairing(H_uid,D_i_2)).getImmutable();
                Element D = bp.pairing(UAKi,C_i_3).getImmutable();
                verifyId = verifyId.mul(B.div(D)).getImmutable();
            }
        }
        if(one.isEqual(verifyId))
        {
            System.out.println("用户属性认证通过");
            return true;
        }
        return false ;
    }

    /**
     * RSU代理外包解密 获得CT'
     * @param config
     * @param userAtts
     * @param AccessPolicy
     * @param userId
     * @param aaNums
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static long outsourseDecrypt(ConfigFileName config, String[] userAtts, String userId, int aaNums,int[][] AccessPolicy,String[] rhos,AccessControlParameter ACP,Element message)
            throws Exception {
        /*********************************************获取公共参数*******************************************************/
        //准备工作获取公参
        Pairing bp = PairingFactory.getPairing(config.getPairingParametersFileName());
        Properties ctProp = accessstruct.Tool.loadPropFromFile(config.getCtFileName());
        Properties UserTKProp = accessstruct.Tool.loadPropFromFile(config.getTKFileName());
        Element D = bp.getGT().newOneElement().getImmutable();
        Map<String, Element> mui = LSSSPolicyEngine.reconstructOmegas(bp,userAtts,ACP);
        if(!(RSU.attAuth(config,userId,userAtts,aaNums,AccessPolicy, rhos)))
        {
            System.out.println("属性认证失败");
            return  0;
        }
        //获取密文C

        String CString = ctProp.getProperty("C");
        Element C = bp.getGT().newElementFromBytes(Base64.getDecoder().decode(CString)).getImmutable();

        String C_0String = ctProp.getProperty("C0");
        Element C0 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C_0String)).getImmutable();
        long time = 0;

        for(int aid = 1; aid <= aaNums;aid++){

            String KString = UserTKProp.getProperty("Kt-"+aid);
            Element K = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(KString)).getImmutable();//
            String L_0_String = UserTKProp.getProperty("L0t-"+aid);
            Element L0 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(L_0_String)).getImmutable();//
            String L_1_String = UserTKProp.getProperty("L1t-"+aid);
            Element L1 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(L_1_String)).getImmutable();//
            String C_1String = ctProp.getProperty("C1-"+aid);
            Element C1 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C_1String)).getImmutable();//

            long startTime = System.currentTimeMillis();
            //先计算分子
            Element E = bp.pairing(L0, C0).mul(bp.pairing(K, C1)).getImmutable();
            Element F = bp.getGT().newOneElement().getImmutable();
            time = time+System.currentTimeMillis()-startTime;
            int averageLen =  userAtts.length/aaNums;
            String [] attInAid = new String[averageLen];
            for(int j = 0;j<averageLen;j++){
                attInAid[j] = userAtts[(aid-1)*averageLen + j];
            }
            for(String att : attInAid){
                //获取密钥
                String K_i_String = UserTKProp.getProperty("K"+att+"t-"+aid);
                Element Ki = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(K_i_String)).getImmutable();

                //获取密文
                String C_i_1String = ctProp.getProperty("C" + att + "1-"+aid);
                Element Ci1 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C_i_1String)).getImmutable();
                String C_i_2String = ctProp.getProperty("C" + att + "2-"+aid);
                Element Ci2 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C_i_2String)).getImmutable();
                String C_i_3String = ctProp.getProperty("C" + att + "3-"+aid );
                Element Ci3 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C_i_3String)).getImmutable();
                long startTime1 = System.currentTimeMillis();
                F = F.mul(bp.pairing(L1, Ci1).mul(bp.pairing(L0, Ci2)).mul(bp.pairing(Ki, Ci3))).getImmutable();
                time = time+System.currentTimeMillis()-startTime1;
            }
            long startTime2 = System.currentTimeMillis();
            D = D.mul(E.div(F)).getImmutable();
            time = time+System.currentTimeMillis()-startTime2;
        }
        long endTime = System.currentTimeMillis();

        ctProp.setProperty("midCt",Base64.getEncoder().withoutPadding().encodeToString(D.toBytes()));

        Tool.storePropToFile(ctProp,config.getCtFileName());
        System.out.println("+++外包解密时间  "+(time)+"  ms");
        System.out.println("Step 外包解密阶段结束=======================================================================");
        return time;
    }
}


